﻿using PedestrianSensingRadar.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PedestrianSensingRadar
{
    /// <summary>
    /// 串口数据解析类
    /// </summary>
    public class SerDataparser : IDataparser
    {
        //申明委托
        public delegate void showdataReventHandle(PacketBuff_t buff, ushort pos_header,int frame_len);
        //申明事件
        public event showdataReventHandle ShowdataR;

        public delegate void showareastateHandle(byte[] areadata);
        public event showareastateHandle showareastate;

        public int m_OpenCom;//串口是否打开标志
        public string GetDataparserInfo()
        {
            return "串口数据解析器";
        }

        public void SerObjTarget()
        {         
            while(m_OpenCom==1)
            {   
                Packet_t packet_R;
                Common.org_data_com.TryDequeue(out packet_R);
                Parse485Packet(ref packet_R);
            }         
        }

        public void Parse485Packet(ref Packet_t pack)
        {
            PacketBuff_t pack_Buff;
            pack_Buff.length = 0;
            pack_Buff.pack_buff = new byte[pack.length * 2];//申请一个原始包长1倍字节的包
            ushort pos_header = 0;//包头位置

            for (int loop = 0; loop < pack.length; loop++)  //packet合并
            {
                pack_Buff.pack_buff[pack_Buff.length++] = pack.pack[loop];
            }

            while(true)//循环提取缓存区内的全部帧数据
            {
                if (pack_Buff.length < 15)//小于最短帧长度，暂不处理
                    break;
                if (pack_Buff.pack_buff[pos_header] == 0xA1 && pack_Buff.pack_buff[pos_header + 1] == 0xA2)        //雷达状态信息解析
                {
                    //if (Packet_1T4R_status_proc(&pack_buff, &pos_header) < 0)
                        break;
                }
                else if (pack_Buff.pack_buff[pos_header] == 0xB1 && pack_Buff.pack_buff[pos_header + 1] == 0xB2)  //1T8R包头：0xB1 0xB2
                {
                    if (Packet_1T4R_frame_proc(ref pack_Buff, ref pos_header) < 0)
                        break;
                }
                else if (pack_Buff.pack_buff[pos_header] == 0xC1 && pack_Buff.pack_buff[pos_header + 1] == 0xC2)  //参数以及版本信息
                {
                    //if (Packet_RadarVer_proc(&pack_buff, &pos_header) < 0)
                        break;
                }
                else if(pack_Buff.pack_buff[pos_header] == 0x7E)//上报信号机数据
                {
                    if (Packet_1T8R_SigalData_Pro(ref pack_Buff, ref pos_header) < 0)
                        break;
                }
                else //不是包头,从下一字节开始，重新寻找包头
                {
                    pack_Buff.length--;  //更新缓冲区数据长度
                    pos_header++;           //更新包头位置                  
                }
            }//end of while

            if (pack_Buff.length>0 && pos_header!=0) //有剩余数据，并且包头位置调整过
            {
                for (int loop = 0; loop < pack_Buff.length; loop++)
                    pack_Buff.pack_buff[loop] = pack_Buff.pack_buff[pos_header + loop];
            }
        }//end of Parse485Packet

        private int Packet_1T8R_SigalData_Pro(ref PacketBuff_t buff, ref ushort pos_header)
        {
            ushort frame_len;    //帧长度 
            int temp, loop;

            //根据校验和判断出帧长度
            temp = pos_header + 12; //指向校验和起始数据，可能一个字节可能两个字节
            if ((buff.pack_buff[temp + 1] == 0x7D && buff.pack_buff[temp + 2] == 0x5E) || (buff.pack_buff[temp + 1] == 0x7D && buff.pack_buff[temp + 2] == 0x5D))
            {
                frame_len = 16;
            }
            else
            {
                frame_len = 15;
            }

            if (buff.length < frame_len)      //缓冲区数据长度小于帧长度 一帧数据未接受完，不处理
                return -1;

            if (15 == frame_len)
            {
                if (buff.pack_buff[pos_header + frame_len - 1] == 0x7E)//包尾
                {
                    byte checksum = 0;//校验和 
                    for (loop = 0; loop < frame_len - 2; loop++)  //计算校验和
                    {
                        checksum ^= buff.pack_buff[pos_header + loop];
                    }
                    if (buff.pack_buff[pos_header + loop] == checksum)  //校验通过 
                    {
                        byte[] area_data = new byte[4];
                        int tmp = pos_header + 4;

                        area_data[0] = buff.pack_buff[tmp + 1];//行人驻足区状态
                        area_data[1] = buff.pack_buff[tmp + 2];//行人驻足区人数
                        area_data[2] = buff.pack_buff[tmp + 5]; //斑马线区状态
                        area_data[3] = buff.pack_buff[tmp + 6];//斑马线区人数

                        showareastate?.Invoke(area_data);
                    }
                    else//校验出错,本包数据丢弃
                    {

                    }
                    buff.length -= frame_len;      //更新缓冲区数据长度
                    pos_header += frame_len;            //更新包头位置
                }//有包头，有包尾，一帧处理完  
                else //有包头，未发现包尾: 丢弃第1字节，从下一字节开始，重新寻找包头
                {
                    buff.length--;  //更新缓冲区数据长度
                    (pos_header)++;        //更新包头位置
                }
            }
            else if (16 == frame_len)
            {
                if (buff.pack_buff[pos_header + frame_len - 1] == 0x7E)//包尾
                {
                    if ((buff.pack_buff[temp + 1] == 0x7D && buff.pack_buff[temp + 2] == 0x5E) || (buff.pack_buff[temp + 1] == 0x7D && buff.pack_buff[temp + 2] == 0x5D))
                    {
                        byte[] area_data = new byte[4];
                        int tmp = pos_header + 4;

                        area_data[0] = buff.pack_buff[tmp + 1];//行人驻足区状态
                        area_data[1] = buff.pack_buff[tmp + 2];//行人驻足区人数
                        area_data[2] = buff.pack_buff[tmp + 5]; //斑马线区状态
                        area_data[3] = buff.pack_buff[tmp + 6];//斑马线区人数

                        showareastate?.Invoke(area_data);
                        if (Common.is_sigal)
                            //显示数据
                            ShowdataR?.Invoke(buff, pos_header, frame_len);
                    }
                    else//校验出错,本包数据丢弃
                    {

                    }
                    buff.length -= frame_len;      //更新缓冲区数据长度
                    pos_header += frame_len;            //更新包头位置
                }//有包头，有包尾，一帧处理完
                else //有包头，未发现包尾: 丢弃第1字节，从下一字节开始，重新寻找包头
                {
                    buff.length--;  //更新缓冲区数据长度
                    (pos_header)++;        //更新包头位置
                }               
            }            
            return 0;
        }

        private int Packet_1T4R_frame_proc(ref PacketBuff_t buff, ref ushort pos_header)
        {
            ushort frame_len;    //帧长度  
            //ushort frame_serial;//帧序号
            
            Frame_t frame=new Frame_t();  //提取出来的帧数据 
            frame.lstTargets.Clear();

            int temp, loop;

            frame_len = (ushort)(buff.pack_buff[pos_header + 6] * 10 + 12); //计算帧数据包长度
            if (buff.length < frame_len)      //缓冲区数据长度小于帧长度 一帧数据未接受完，不处理
                return -1;

            if ((buff.pack_buff[pos_header + frame_len - 2] == 0xB3) && (buff.pack_buff[pos_header + frame_len - 1] == 0xB4))   //1T8R包尾：0xB3 0xB4 
            {
                frame.frame_serial= (buff.pack_buff[pos_header + 2] << 24) + (buff.pack_buff[pos_header + 3] << 16) +
                       (buff.pack_buff[pos_header + 4] << 8)+(buff.pack_buff[pos_header + 5]);  //获取帧序号

                byte checksum = 0;//校验和 
                for (loop = 0; loop < (frame_len - 3); loop++)  //计算校验和
                {                  
                    checksum += buff.pack_buff[pos_header + loop];
                }

                if (buff.pack_buff[pos_header + loop] == checksum)  //校验通过 
                {
                    frame.target_num = buff.pack_buff[pos_header + 6]; //目标个数 （包括输出目标点）  

                    if (frame.target_num > 0)   //有目标点 
                    {
                        for (loop = 0; loop < frame.target_num; loop++)
                        {
                            Target_t target = new Target_t();
                            temp = pos_header + 9 + loop * 10; //指向目标点起始数据 
                            target.range = (ushort)((buff.pack_buff[temp] << 8) + buff.pack_buff[temp + 1]) / 10;
                            target.speed = (short)((buff.pack_buff[temp + 2] << 8) + buff.pack_buff[temp + 3]) / 100;
                            target.angle = (short)((buff.pack_buff[temp + 4] << 8) + buff.pack_buff[temp + 5]) / 10;
                            target.level = (short)(buff.pack_buff[temp + 6] << 8) + buff.pack_buff[temp + 7];
                            target.snr = (ushort)(buff.pack_buff[temp + 8] << 8) + buff.pack_buff[temp + 9];

                            frame.lstTargets.Add(target);
                        }                                     
                    }
                    if (Common.isobj)
                    {
                        //采用异步调用
                        //Delegate[] delArray = ShowdataR.GetInvocationList();
                        //foreach (Delegate del in delArray)
                        //{
                        //    showdataReventHandle method = (showdataReventHandle)del;
                        //    method.BeginInvoke(buff, pos_header, frame_len,null,null);
                        //}
                        //显示数据
                        ShowdataR?.Invoke(buff, pos_header, frame_len);
                    }
                    //完成一帧
                    Common.frame.Enqueue(frame);
                    //Common.frame_record.Enqueue(frame);//此处根据是否开启数据记录线程判断是否添加数据到记录队列中(待优化)
                }
                else//校验出错,本包数据丢弃 
                {

                }
                buff.length -= frame_len;      //更新缓冲区数据长度
                pos_header += frame_len;            //更新包头位置
            }//有包头，有包尾，一帧处理完  
            else //有包头，未发现包尾: 丢弃第1字节，从下一字节开始，重新寻找包头
            {
                buff.length--;  //更新缓冲区数据长度
                (pos_header)++;        //更新包头位置
            }
            return 0;
        }
    }
}
